﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using EasyStep.Data.Entities;
using EasyStep.Attributes;
using WPF.TestEditor.Common;

namespace WPF.TestEditor.Controls
{
  
    public partial class TestListEditor : UserControlBase
    {
        public event EventHandler DataChanged;
        public event EventHandler<MessageArgs> StatusChanges;
        private System.Timers.Timer timer = new System.Timers.Timer(250);

        private DynamicACCollection completionHelper;
        

        public TestListEditor()
        {
            InitializeComponent();
            timer.Stop();
            timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);            
        }
        private Action onTimer;
        void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            timer.Stop();
            if (onTimer != null)
            {
                var method = onTimer;
                onTimer = null;
                Dispatcher.Invoke(method);
            }            
        }

        public void InitEditor(TestInfo Data)
        {
            completionHelper = new DynamicACCollection(TestDataContext);
            pnlSteps.Children.Clear();
            StatusChanges(this, new MessageArgs("List editor has been reloaded with data from current test!"));
            if (Data != null && Data.Steps != null && Data.Steps.Any())
                foreach (var step in Data.Steps)
                {
                    AddStepAt(-1, step);
                }
            else
                AddDefaultTestStep();
        }

        public void AddDefaultTestStep(int pos=-1)
        {
            AddStepAt(-1, new TestStep() { ActionId=actions.FirstOrDefault().Id });
            StatusChanges(this, new MessageArgs("Empty test step has been generated!"));
        }
        private TestStepEdit AddStepAt(int pos, TestStep step)
        {
            var s = new TestStepEdit(step, Actions, completionHelper);
            s.DataChanged += new EventHandler(Step_DataChanged);
            s.RemoveClicked += new EventHandler(Step_Remove);
            s.AddNewClicked += new EventHandler(Step_AddNewAfter);
            s.MoveUp += new EventHandler(Step_MoveUp);
            s.MoveDown += new EventHandler(Step_MoveDown);
            if (pos < 0)
                pnlSteps.Children.Add(s);
            else
                pnlSteps.Children.Insert(pos, s);
            s.Position = pnlSteps.Children.IndexOf(s);
            return s;
        }

        #region events
        void Step_DataChanged(object sender, EventArgs e)
        {
            timer.Stop();
            onTimer = () =>
            {
               
                    Data = GetTest();
                    StatusChanges(this, new MessageArgs("Current test has been modified according to data from test List editor !"));
                    if (DataChanged!=null) DataChanged(this, null);               
            };
            timer.Start();
        }

        void Step_AddNewAfter(object sender, EventArgs e)
        {
            var s = sender as TestStepEdit;
            int pos = pnlSteps.Children.IndexOf(s) + 1;
            if (s.Data.Action == null)
                AddDefaultTestStep(pos);
            else
            {
                var text=TestDataContext.TestStepManager.Convert(s.Data);
                var data = string.IsNullOrEmpty(text) ? new TestStep() : TestDataContext.TestStepManager.Convert(text);
                var control = AddStepAt(pos, data);
                Step_DataChanged(control, null);
            }
            StatusChanges(this, new MessageArgs("new step has been added into position:{0}!",new object[]{pos}));            
        }
        void Step_MoveUp(object sender, EventArgs e)
        {
            var s = sender as TestStepEdit;
            var i = pnlSteps.Children.IndexOf(s);
            if (i < 1) return;
            pnlSteps.Children.RemoveAt(i);
            pnlSteps.Children.Insert(i - 1, s);
            s.Position = pnlSteps.Children.IndexOf(s);
            StatusChanges(this, new MessageArgs("step has been moved up to position:{0}!", new object[] { s.Position}));
            Step_DataChanged(s, null);
        }
        void Step_MoveDown(object sender, EventArgs e)
        {
            var s = sender as TestStepEdit;
            var i = pnlSteps.Children.IndexOf(s);
            if (i > pnlSteps.Children.Count-2) return;
            pnlSteps.Children.RemoveAt(i);
            pnlSteps.Children.Insert(i + 1, s);
            s.Position = pnlSteps.Children.IndexOf(s);
            StatusChanges(this, new MessageArgs("step has been moved down to position:{0}!", new object[] { s.Position }));
            Step_DataChanged(s, null);
        }        
        void Step_Remove(object sender, EventArgs e)
        {
            var s= sender as TestStepEdit;
            s.DataChanged -= Step_DataChanged;
            s.RemoveClicked -= Step_Remove;
            s.AddNewClicked -= Step_AddNewAfter;
            s.MoveUp -= Step_MoveUp;
            s.MoveDown -= Step_MoveDown;
                        
            pnlSteps.Children.Remove(s);
            StatusChanges(this, new MessageArgs("step has been removed from position:{0}!", new object[] { s.Position }));
            Step_DataChanged(s, null);
            if (pnlSteps.Children.Count == 0)
                AddDefaultTestStep();
        }
        #endregion
        

        private IEnumerable<TestAction> actions;
        public IEnumerable<TestAction> Actions
        {
            get {
                if (actions != null) return actions;
                actions=TestDataContext.ActionManager.GetAll();
                return actions;
            }
        }

        public TestInfo Data { get; set; }
        private  TestInfo GetTest()
        {
            var curTest = new TestInfo();
            var steps=new List<TestStep>();
            var i = 0;
            foreach (TestStepEdit item in pnlSteps.Children)
            {
                steps.Add(item.Data);
                item.Position = i++;
            }
            curTest.Steps = steps;
            return curTest;
        }
    }
}
